﻿using System.Collections.Concurrent;
using System.Collections.Generic;

namespace Red.Core.Network.PacketNetwork
{
    internal class PacketConnetionCollection
    {
        private ConcurrentDictionary<int, int> _connectionIds = new ConcurrentDictionary<int, int>();
        private ConcurrentDictionary<int, PacketConnection> _connections = new ConcurrentDictionary<int, PacketConnection>();
        public delegate void OnRemoveConnectionHandler( PacketConnection connection );

        public ulong TotalBytesReceived
        {
            get
            {
                ulong result = 0;
                foreach ( var connection in _connections )
                {
                    result += connection.Value.TotalBytesReceived;
                }
                return result;
            }
        }

        public ulong GetTotalBytesReceivedForListener( int packetListenerID )
        {
            ulong result = 0;
            foreach ( var connection in _connections )
            {
                if( connection.Value.AssignedListenerID == packetListenerID )
                    result += connection.Value.TotalBytesReceived;
            }
            return result;
        }

        public void AddConnection( int connectionId, PacketConnection connection )
        {
            _connections.AddOrUpdate( connectionId, connection, ( key, oldValue ) => connection );
            _connectionIds.AddOrUpdate( connection.RawConnectionID, connectionId, ( key, oldValue ) => connectionId );
        }

        public void RemoveConnection( int connectionID, OnRemoveConnectionHandler removalHandler )
        {
            PacketConnection connection;
            _connections.TryRemove( connectionID, out connection );

            int packetConnectionId;
            _connectionIds.TryRemove( connection.RawConnectionID, out packetConnectionId );
            System.Diagnostics.Debug.Assert( packetConnectionId == connection.AssignedID );

            removalHandler?.Invoke( connection );
        }

        public void RemoveConnectionByRawId( int rawConnectionId )
        {
            int packetConnectionId;
            if ( _connectionIds.TryGetValue( rawConnectionId, out packetConnectionId ) )
            {
                RemoveConnection( packetConnectionId, null );
            }
        }

        public void RemoveConnectionsRelatedToListener(int listenerID, OnRemoveConnectionHandler removalHandler)
        {
            foreach ( KeyValuePair<int, PacketConnection> pair in _connections )
            {
                if (pair.Value.AssignedListenerID == listenerID)
                {
                    PacketConnection connection;
                    _connections.TryRemove(pair.Key, out connection);
                    removalHandler(connection);
                }
            }
        }

        public bool FindConnection( int packetConnectionID, out PacketConnection connection )
        {
            return _connections.TryGetValue(packetConnectionID, out connection);
        }
    }
}
